#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "Common.h"
#include "Window.h"
#include "Internals.h"
#include "CtrlClass.h"

extern BOOL RegisterStaticControl (void);

#define LEN_CCITABLE    26

static PCTRLCLASSINFO ccitable[LEN_CCITABLE];

PCONTROL Control (HWND hWnd)
{
    PCONTROL pCtrl;

    pCtrl = (PCONTROL) hWnd;

    if (pCtrl && pCtrl->WinType == TYPE_CONTROL)
        return pCtrl;

    return NULL;
}

BOOL InitControlClass ()
{
    int i;

    for (i=0; i<LEN_CCITABLE; i++)
        ccitable[i] = NULL;

    // Register system controls here.
    if (!RegisterStaticControl ())
        return FALSE;

    return TRUE;
}

void TerminateControlClass ()
{
    EmptyControlClassInfoTable ();
}

PCTRLCLASSINFO GetControlClassInfo (const char* szClassName)
{
    PCTRLCLASSINFO cci;
    int i=0;
    char szName [MAXLEN_CLASSNAME + 1];

    if (szClassName == NULL) return NULL;

    strncpy (szName, szClassName, MAXLEN_CLASSNAME);

    if (!isalpha ((int)szName[0])) return NULL;

    while (szName[i]) {
        szName[i] = toupper(szName[i]);

        i++;
    }

    cci = ccitable [szName[0] - 'A'];

    while (cci) {

        if (strcmp (cci->name, szName) == 0)
            break;

        cci = cci->next;
    }

    return cci;
}

int AddNewControlClass (PWNDCLASS pWndClass)
{
    PCTRLCLASSINFO cci, newcci;
    char szClassName [MAXLEN_CLASSNAME + 2];
    int i=0;

    strncpy (szClassName, pWndClass->spClassName, MAXLEN_CLASSNAME + 1);

    if (!isalpha ((int)szClassName[0])) return ERR_CTRLCLASS_INVNAME;

    while (szClassName[i]) {
        szClassName[i] = toupper(szClassName[i]);

        i++;
        if (i > MAXLEN_CLASSNAME)
            return ERR_CTRLCLASS_INVLEN;
    }

    i = szClassName[0] - 'A';
    cci = ccitable [i];
    if (cci) {

        while (cci) {
            if (strcmp (szClassName, cci->name) == 0)
                return ERR_CTRLCLASS_INVNAME;

            cci = cci->next;
        }
    }
    cci = ccitable[i];

    newcci = malloc (sizeof (CTRLCLASSINFO));

    if (newcci == NULL) return ERR_CTRLCLASS_MEM;

    newcci->next = NULL;
    strcpy (newcci->name, szClassName);
    newcci->dwStyle     = pWndClass->dwStyle;
    newcci->ControlProc = pWndClass->WinProc;
    newcci->nUseCount   = 0;

    if (cci) {
        while (cci->next)
            cci = cci->next;

        cci->next = newcci;
    }
    else
        ccitable [i] = newcci;

    return ERR_OK;
}

int DeleteControlClass (const char* szClassName)
{
    PCTRLCLASSINFO head, cci, prev;
    int i=0;
    char szName [MAXLEN_CLASSNAME + 1];

    if (szClassName == NULL) return ERR_CTRLCLASS_INVNAME;

    strncpy (szName, szClassName, MAXLEN_CLASSNAME);

    if (!isalpha ((int)szName[0])) return ERR_CTRLCLASS_INVNAME;

    while (szName[i]) {
        szName[i] = toupper(szName[i]);

        i++;
    }

    i = szName[0] - 'A';
    head = ccitable [i];

    cci = head;
    prev = head;
    while (cci) {

        if (strcmp (cci->name, szName) == 0)
            break;

        prev = cci;
        cci = cci->next;
    }

    if (!cci)
        return ERR_CTRLCLASS_INVNAME;

    if (cci->nUseCount != 0)
        return ERR_CTRLCLASS_INVNAME;

    if (cci == head) {
        ccitable [i] = cci->next;
        free (cci);
    }
    else {
        prev->next = cci->next;
        free (cci);
    }

    return ERR_OK;
}

void EmptyControlClassInfoTable ()
{
    PCTRLCLASSINFO cci, temp;
    int i;

    for (i = 0; i<LEN_CCITABLE; i++) {
        cci = ccitable [i];
        while (cci) {
            temp = cci->next;

            free (cci);

            cci = temp;
        }
    }
}
